/**
 * 本文中，函数名带冷却塔指《DL/T 1027-2006，工业冷却塔测试规程》
 *
 * 以"_opt”结尾的参数为可选参数
 * 温度参数不带后缀则单位为摄氏度
 * 含湿量（湿度系数，Humidity ratio by mass）：水蒸气质量/干空气质量
 * 干空气分数（湿度系数，Humidity ratio by vapor partial pressure：水蒸气摩尔的量/干空气摩尔的量
 * 比湿度（Specific Humidity）：水蒸气的质量/湿空气的质量
 * 绝对湿度（Absolute Humidity）：水蒸气的质量/湿空气的体积
 */

//=============================== 使用REFPROP的动态链接库计算混合气体的密度、显热、低位热值和高位热值 ==========================
function fluid_string(燃料体积分数数组, 燃料气名称数组_opt) {
    /**
     * 参考REFPROP示例xls文件的FluidString函数，生成混合气体的描述字符串
     * 气体体积分数数组默认参考wps宏.js，也可以指定
     */
    let result = ""
    let data_list = _get_arr_of_range(燃料体积分数数组)
    if (!燃料气名称数组_opt) {
        let 组分名列表 = 常量().组分名列表;
        let refprop_name = 常量().REFPROP_Name;
        for (let i = 0; i < data_list.length; i++) {
            if (data_list[i] !== 0) {
                let 组分名 = 组分名列表[i];
                let prop_name = refprop_name[组分名];
                result = result + prop_name + ";" + data_list[i] + ";"
            }
        }
    }
    return result;
}

function 焓_refprop(压力_MPa, 温度_K, 燃料气体积分数数组) {
    let string = fluid_string(燃料气体积分数数组);
    return Enthalpy(string, "PT", "SI", 压力_MPa, 温度_K);  // js无法调用vb的函数
}

function 密度_refprop(压力_MPa, 温度_K, 燃料气体积分数数组) {
    let string = fluid_string(燃料气体积分数数组);
    return Density(string, "PT", "SI", 压力_MPa, 温度_K);
}

function 低位热值_refprop(压力_MPa, 温度_K, 燃料气体积分数数组) {
    let string = fluid_string(燃料气体积分数数组);
    return NetHeatingValue(string, "PT", "SI", 压力_MPa, 温度_K);
}

function 高位热值_refprop(压力_MPa, 温度_K, 燃料气体积分数数组) {
    let string = fluid_string(燃料气体积分数数组);
    return NetHeatingValue(string, "PT", "SI", 压力_MPa, 温度_K);
}

//=============================== 使用REFPROP的动态链接库计算混合气体的密度、显热、低位热值和高位热值 ==========================
function T_air_HX(焓, 含湿量) {
    // 根据湿空气比焓和含湿量计算空气干球温度，单位℃
    let a = 含湿量 * 2500;
    let b = 焓 - a;
    let c = 1.005 + 含湿量 * 1.846;
    return b / c;
}

function 分压_水(相对湿度, 干球饱和压力_kPa) {
    /**
     *  参考PTC 4.4-2008联合循环余热锅炉性能试验规程，第36页，第2步
     *  干球饱和压力，kPa
     *  相对湿度, 0~100
     *  @return 分压：kPa
     */
    if (相对湿度 > 1) {
        相对湿度 = 相对湿度 / 100;
    }
    return 相对湿度 * 干球饱和压力_kPa;
}

function 绝对湿度() {
    /**
     * 湿空气的绝对湿度定义为：每立方米湿空气中所含水蒸气的质量，单位为：kg/m3
     */
    return "暂不支持"
}

function 干空气分数_RH(大气压力_kPa, 干球温度, 相对湿度) {
    /**
     * 干空气摩尔分数，参考PTC 4.4-2008联合循环余热锅炉性能试验规程中文版，第36页，第3步
     * 定义为：湿空气中，干空气的分压/总压
     * 大气压力，kPa
     * 相对湿度, 0~100或0~1均可
     * 干球温度，℃
     * @type {number} 干空气分数mole/mole
     */
    let 干球饱和压力 = 饱和压力_余热锅炉(干球温度) * 1000;
    let p_water = 分压_水(相对湿度, 干球饱和压力);
    return 1 - p_water / 大气压力_kPa;
}

function 含湿量_余热锅炉(大气压力_kPa, 干球温度, 湿球温度) {
    return 含湿量_mass_WetBulb(大气压力_kPa, 干球温度, 湿球温度);
}

function 含湿量_mass_WetBulb(大气压力_kPa, 干球温度, 湿球温度) {
    /**
     * 一般所指的含湿量就是质量表示的含湿量
     * 湿空气的含湿量定义为是湿空气中水的质量/干空气的质量，也就是常说的含湿量
     * 湿空气的湿度系数，质量表示的绝对湿度Humid ratio by mass
     * @return {number} 湿度系数：kg/kg
     */
    let 大气压力 = 大气压力_kPa / 1000; // 转换单位为MPa
    let 湿球饱和压力 = 饱和压力_余热锅炉(湿球温度);
    let hr_sat = 0.62198 * (1.0039 * 湿球饱和压力) / (大气压力 - 1.0039 * 湿球饱和压力); // 饱和湿空气的绝对湿度humid ratio
    let hr = (1075.208 - 1.0008 * 湿球温度) * hr_sat - 0.432 * (干球温度 - 湿球温度);
    hr = hr / (1075.208 + 0.7992 * 干球温度 - 1.8 * 湿球温度); // 湿空气的绝对湿度，质量表示的绝对湿度Humid ratio by mass
    return hr;
}

function 干空气分数_WetBulb(大气压力_kPa, 干球温度, 湿球温度) {
    /**
     * 干空气摩尔分数，参考PTC 4.4-2008联合循环余热锅炉性能试验规程中文版，第36页，第4-6步
     * 湿空气中，干空气的分压/总压
     * 干空气分数的单位是mole/mole
     */
    let hr = 含湿量_余热锅炉(大气压力_kPa, 干球温度, 湿球温度)
    return 18.01528 / (28.9651785 * hr + 18.01528);  // 干空气分数，摩尔（或分压力），该公式貌似有问
}

function 饱和压力_余热锅炉(温度) {
    /**
     * 参考ASME PTC4.4-2008
     * 等于IAPWS中的P_T(T)
     * 温度:摄氏度，参考PTC 4.4-2008联合循环余热锅炉性能试验规程中文版，第36页，第1步
     * 饱和压力=汽化压力=P_T(温度)
     * @return 饱和压力：MPa
     */

    if (温度 < -100) {
        return "干球温度超下限"
    } else if (温度 > 200) {
        return "干球温度超上限"
    }

    let c1, c2, c3, c4, c5, c6, c7;

    if (温度 < 0) {
        c1 = -1.0214165e4
        c2 = -9.8702328
        c3 = -5.3765794e-3;
        c4 = -1.9202377e-7;
        c5 = -3.5575832e-10;
        c6 = -9.0344688e-14;
        c7 = -4.1635019;
    } else {
        c1 = -1.0440397e4;
        c2 = -16.27164;
        c3 = -2.7022355e-2;
        c4 = 1.289036e-5;
        c5 = -2.4780681e-9;
        c6 = 0;
        c7 = 6.5459673;
    }
    let tr = 1.8 * 温度 + 491.67;
    // Math.log()是ln，Math.log10()是log
    let ln_p = c1 / tr + c2 + c3 * tr + c4 * tr * tr + c5 * Math.pow(tr, 3) + c6 * Math.pow(tr, 4) + c7 * Math.log(tr);
    return Math.pow(Math.E, ln_p)
}

function 饱和压力_冷却塔(温度) {
    /**
     * 参考《DL/T 1027-2006，工业冷却塔测试规程》第13-14页。
     * 该方法的准确度最低，建议优先使用P_T()或饱和压力_余热锅炉()进行计算
     * 饱和压力=汽化压力=P_T(温度),P_T()是最准确的计算公式。
     * 注意三个函数返回的饱和压力单位并不相同
     * 温度: ℃
     * @return 饱和压力：Pa
     */
    let 温度_K = 温度 + 273.15;  // 将温度转换为绝对温度
    let lg_p = 5.005717 - 3.142305 * (1000 / 温度_K - 1000 / 373.116) + 8.21 * Math.log10(373.16 / 温度_K) - 0.0024804 * (373.16 - 温度_K);
    return Math.pow(10, lg_p);
}

function 摩尔分数_湿空气组分(组分名, 干空气分数) {
    /**
     * 计算湿空气各组分的摩尔分数
     * @type {number}
     */
        // 湿空气摩尔分数
    let result = 常量().干空气组分.摩尔分数[组分名];
    if (result) {
        result = result * 干空气分数;
    } else {
        return 0;
    }
    return result
}

function 摩尔质量_湿空气(干空气分数) {
    //参考ASME PTC4.4-2008英文版45页第8步，中文版37页第8步
    // 也就是计算湿空气的分子量
    // 干空气摩尔分数，为常数
    let frac_mole_N2_dry = 0.78084;
    let frac_mole_O2_dry = 0.2094760;
    let frac_mole_CO2_dry = 0.0003190;
    let frac_mole_H2O_dry = 0;
    let frac_mole_Ar_dry = 0.009365;

    // 湿空气摩尔分数
    let frac_mole_N2_wet = frac_mole_N2_dry * 干空气分数;
    let frac_mole_O2_wet = frac_mole_O2_dry * 干空气分数;
    let frac_mole_CO2_wet = frac_mole_CO2_dry * 干空气分数;
    let frac_mole_H2O_wet = 1 - 干空气分数;
    let frac_mole_Ar_wet = frac_mole_Ar_dry * 干空气分数;

    // 摩尔质量
    let mass_mole_N2 = 28.01348;
    let mass_mole_O2 = 31.9988;
    let mass_mole_CO2 = 44.0098;
    let mass_mole_H2O = 18.01528;
    let mass_mole_Ar = 39.948;

    let N2 = frac_mole_N2_wet * mass_mole_N2;
    let O2 = frac_mole_O2_wet * mass_mole_O2;
    let CO2 = frac_mole_CO2_wet * mass_mole_CO2;
    let H2O = frac_mole_H2O_wet * mass_mole_H2O;
    let Ar = frac_mole_Ar_wet * mass_mole_Ar;

    return N2 + O2 + CO2 + H2O + Ar;
}

function 湿空气分子量(干空气分数) {
    return 摩尔分数_湿空气组分(干空气分数);
}

function 密度_湿空气_冷却塔(压力_Pa, 温度_K, 相对湿度, 饱和压力_Pa_opt) {
    /**
     * 参考DL/T 1027-2006，工业冷却塔测试规程
     */
    let p_sat;
    if (!饱和压力_Pa_opt) {
        p_sat = 饱和压力_余热锅炉(温度_K - 273.15) * 1000000;
    } else {
        p_sat = 饱和压力_Pa_opt;
    }
    return 1 / T * (0.003483 * 压力_Pa - 0.001316 * 相对湿度 * p_sat);
}

function 含湿量_冷却塔(压力_Pa, 温度_K, 相对湿度_100, 饱和压力_Pa_opt) {
    /**
     * 参考DL/T 1027-2006，工业冷却塔测试规程
     * 含湿量定义为：每kg干空气中水的质量
     * 内部默认使用ASME PTC4.4-2008计算水的饱和蒸汽压力，原冷却塔规程给的饱和蒸气压计算公式准确度较低。
     * @type {string|*}
     */
    let p_sat;
    if (!饱和压力_Pa_opt) {
        p_sat = 饱和压力_余热锅炉(温度_K - 273.15) * 1000000;
    } else {
        p_sat = parseFloat(饱和压力_Pa_opt);
    }
    return 0.622 * 相对湿度 * p_sat / (压力_Pa - 相对湿度 * p_sat);
}

function 质量分数_湿空气组分(组分名, 干空气分数) {
    // 参考ASME PTC4.4-2008英文版45页第10步，中文版37页第10步
    // 湿空气摩尔分数
    let frac_mole_N2_wet = 摩尔分数_湿空气组分("N2", 干空气分数);
    let frac_mole_O2_wet = 摩尔分数_湿空气组分("O2", 干空气分数);
    let frac_mole_CO2_wet = 摩尔分数_湿空气组分("CO2", 干空气分数);
    let frac_mole_H2O_wet = 摩尔分数_湿空气组分("H2O", 干空气分数);
    let frac_mole_Ar_wet = 摩尔分数_湿空气组分("Ar", 干空气分数);

    let mass_N2 = frac_mole_N2_wet * 28.0135;
    let mass_O2 = frac_mole_O2_wet * 31.9988;
    let mass_CO2 = frac_mole_CO2_wet * 44.01;
    let mass_H2O = frac_mole_H2O_wet * 18.0153;
    let mass_Ar = frac_mole_Ar_wet * 39.948;
    let mass = mass_N2 + mass_O2 + mass_CO2 + mass_H2O + mass_Ar;

    if (组分名 === "N2") {
        return mass_N2 / mass;
    } else if (组分名 === "O2") {
        return mass_O2 / mass;
    } else if (组分名 === "CO2") {
        return mass_CO2 / mass;
    } else if (组分名 === "H2O") {
        return mass_H2O / mass;
    } else if (组分名 === "Ar") {
        return mass_Ar / mass;
    } else if (组分名 === "SO2") {
        return 0;
    } else {
        return "组分名错误"
    }
}

function 焓_湿空气_联合循环(空气温度, 干空气分数, 基准温度_opt) {
    // 联合循环某规程计算方法
    // 引用了燃气物性中的焓_组分()方法
    if (基准温度_opt === undefined || 基准温度_opt + 0 !== 基准温度_opt) {
        基准温度_opt = 15;
    }
    // 组分焓
    let h_N2 = 焓_组分("N2", 空气温度 + 273.15, 基准温度_opt + 273.15);
    let h_O2 = 焓_组分("O2", 空气温度 + 273.15, 基准温度_opt + 273.15);
    let h_CO2 = 焓_组分("CO2", 空气温度 + 273.15, 基准温度_opt + 273.15);
    let h_H2O = 焓_组分("H2O", 空气温度 + 273.15, 基准温度_opt + 273.15);
    let h_Ar = 焓_组分("Ar", 空气温度 + 273.15, 基准温度_opt + 273.15);

    // 质量分数
    let frac_mass_N2 = 质量分数_湿空气组分("N2", 干空气分数);
    let frac_mass_O2 = 质量分数_湿空气组分("O2", 干空气分数);
    let frac_mass_CO2 = 质量分数_湿空气组分("CO2", 干空气分数);
    let frac_mass_H2O = 质量分数_湿空气组分("H2O", 干空气分数);
    let frac_mass_Ar = 质量分数_湿空气组分("Ar", 干空气分数);

    return frac_mass_N2 * h_N2 + frac_mass_O2 * h_O2 + frac_mass_CO2 * h_CO2 + frac_mass_H2O * h_H2O + frac_mass_Ar * h_Ar;
}

function 焓_湿空气_冷却塔(干球温度, 含湿量) {
    /**
     * 干球温度: ℃
     * 含湿量: kg/kg
     */
    return 1.005 * 干球温度 + 含湿量 * (2500 + 1.846 * 干球温度);
}

/**
 * =========================================== ASME PTC 4.4-2008余热锅炉规程 ============================================
 * 以下为余热锅炉规程中相关计算公式
 * =========================================== ASME PTC 4.4-2008余热锅炉规程 ============================================
 */

function 常量() {
    return {
        combustion_ratios: {
            N2: {
                CH4: 0, N2: 1, CO2: 0, C2H6: 0, C3H8: 0, H2O: 0, H2S: 0, H2: 0, CO: 0, O2: 0,
                C4H10: 0, C5H12: 0, C6H14: 0, C7H16: 0, C8H18: 0, C9H20: 0, C10H22: 0, He: 0,
                Ar: 0, C2H4: 0, C3H6: 0, C4H8: 0, C5H10: 0
            },
            O2: {
                CH4: -2,
                C2H6: -3.5,
                C2H4: -3,
                C3H8: -5,
                C3H6: -4.5,
                C4H10: -6.5,
                C4H8: -6,
                C5H12: -8,
                C5H10: -7.5,
                C6H14: -9.5,
                N2: 0,
                CO: -0.5,
                CO2: 0,
                H2O: 0,
                H2: -0.5,
                H2S: -1.5,
                He: 0,
                O2: 1,
                Ar: 0,
                C7H16: -11,
                C8H18: -12.5,
                C9H20: -14,
                C10H22: -15.5
            },
            CO2: {
                CH4: 1, C2H6: 2, C2H4: 2, C3H8: 3, C3H6: 3, C4H10: 4, C4H8: 4, C5H12: 5, C5H10: 5, C6H14: 6,
                N2: 0, CO: 1, CO2: 1, H2O: 0, H2: 0, H2S: 0, He: 0, O2: 0, Ar: 0,
                C7H16: 7, C8H18: 8, C9H20: 9, C10H22: 10
            },
            H2O: {
                CH4: 2, C2H6: 3, C2H4: 2, C3H8: 4, C3H6: 3, C4H10: 5, C4H8: 4, C5H12: 6, C5H10: 5, C6H14: 7,
                N2: 0, CO: 0, CO2: 0, H2O: 1, H2: 1, H2S: 1, He: 0, O2: 0, Ar: 0,
                C7H16: 8, C8H18: 9, C9H20: 10, C10H22: 11
            },
            Ar: {
                CH4: 0, N2: 0, CO2: 0, C2H6: 0, C3H8: 0, H2O: 0, H2S: 0, H2: 0, CO: 0, O2: 0,
                C4H10: 0, C5H12: 0, C6H14: 0, C7H16: 0, C8H18: 0, C9H20: 0, C10H22: 0, He: 0,
                Ar: 1, C2H4: 0, C3H6: 0, C4H8: 0, C5H10: 0
            },
            SO2: {
                CH4: 0, N2: 0, CO2: 0, C2H6: 0, C3H8: 0, H2O: 0, H2S: 1, H2: 0, CO: 0, O2: 0,
                C4H10: 0, C5H12: 0, C6H14: 0, C7H16: 0, C8H18: 0, C9H20: 0, C10H22: 0, He: 0,
                Ar: 0, C2H4: 0, C3H6: 0, C4H8: 0, C5H10: 0
            }
        },
        干空气摩尔质量: 28.965194,
        干空气组分: {
            摩尔分数: {
                O2: 0.209476,
                N2: 0.78084,
                CO2: 0.0003190,
                Ar: 0.009365,
                H2O: 0,
                SO2: 0,
            }
        },
        分子量: {
            CH4: 16.043, N2: 28.0135, CO2: 44.01, C2H6: 30.07, C3H8: 44.097,
            H2O: 18.01528, H2S: 34.082, H2: 2.0159, CO: 28.01, O2: 31.9988,
            C4H10: 58.123, C5H12: 72.15, C6H14: 86.177,
            C7H16: 100.204, C8H18: 114.231, C9H20: 128.258, C10H22: 142.285, He: 4.0026,
            Ar: 39.948, C2H4: 28.05376, C3H6: 42.08064, C4H8: 56.10752, C5H10: 70.1344,
            SO2: 64,
        },
        组分名列表: ["CH4", "N2", "CO2", "C2H6", "C3H8", "H2O", "H2S", "H2", "CO", "O2",
            "C4H10", "C4H10", "C5H12", "C5H12", "C6H14", "C7H16", "C8H18", "C9H20", "C10H22", "He",
            "Ar", "C2H4", "C3H6", "C4H8", "C5H10"], // 这个是excel中输入的组分体积分数列表
        REFPROP_Name: { // 工质在refprop中的名称，调用refprop时使用，refprop中的工质名不区分大小写
            CH4: "methane", N2: "nitrogen", CO2: "CO2", "C2H6": "ethane",
            C3H8: "propane", H2O: "water", H2S: "H2S", H2: "hydrogen", CO: "CO", O2: "oxygen",
            C4H10: "butane", C4H10iso: "isobutane", C5H12: "pentane", C5H12iso: "isopentane",
            C6H14: "hexane", C7H16: "heptane", C8H18: "octane", C9H20: "nonane", C10H22: "decane",
            C11H24: "c11", C12H26: "c12",
            He: "helium", Ar: "argon", C2H4: "ethylene", C3H6: "propylen", C3H6cyc: "cyclopro", // 环丙烷
            C4H8: "1butene", C5H10: "cyclopen",
            C6H12: "cyclohex", // 环己烷
            C8H10: "pxylene", C6H6: "benzene",
        },
        组分名_分子式: {
            甲烷: "CH4", 乙烷: "C2H6", 丙烷: "C3H8", 丁烷: "C4H10", 异丁烷: "C4H10", 正丁烷: "C4H10",
            戊烷: "C5H12", 正戊烷: "C5H12", 异戊烷: "C5H12", 己烷: "C6H14", 庚烷: "C7H16", 辛烷: "C8H18",
            壬烷: "C9H20", 癸烷: "C10H22",
            乙烯: "C2H4", 丙烯: "C3H6", 丁烯: "C4H8", 戊烯: "C5H10",
            苯: "C6H6", 甲苯: "C7H8", 乙苯: "C8H10",
            氦: "He", 氩: "Ar", 氮: "N2", 二氧化碳: "CO2", 水: "H2O",
            硫化氢: "H2S", 氢: "H2", 一氧化碳: "CO", 氧: "O2",
        },
        压缩因子: {  // 参考GB/T 11062-2020
            "CH4": {t0: 0.04886, t15: 0.04452, t15_55: 0.04437, t20: 0.04317, u: 0.0005},
            "C2H6": {t0: 0.0997, t15: 0.0919, t15_55: 0.0916, t20: 0.0895, u: 0.0011},
            "C3H8": {t0: 0.1465, t15: 0.1344, t15_55: 0.1340, t20: 0.1308, u: 0.0016},
            "C4H10": {t0: 0.2022, t15: 0.1840, t15_55: 0.1834, t20: 0.1785, u: 0.0039}, // 丁烷
            "C5H12": {t0: 0.2586, t15: 0.2361, t15_55: 0.2354, t20: 0.2295, u: 0.0107}, // 戊烷
            "C6H14": {t0: 0.3319, t15: 0.3001, t15_55: 0.2990, t20: 0.2907, u: 0.0271}, // 己烷
            "C7H16": {t0: 0.4076, t15: 0.3668, t15_55: 0.3654, t20: 0.3547, u: 0.1001}, // 庚烷
            "C8H18": {t0: 0.4845, t15: 0.4346, t15_55: 0.4329, t20: 0.4198, u: 0.1002}, // 辛烷
            "C9H20": {t0: 0.5617, t15: 0.5030, t15_55: 0.5010, t20: 0.4856, u: 0.1006}, // 壬烷
            "C10H22": {t0: 0.6713, t15: 0.5991, t15_55: 0.5967, t20: 0.5778, u: 0.1006}, // 癸烷
            "C2H4": {t0: 0.0868, t15: 0.0799, t15_55: 0.0797, t20: 0.0778, u: 0.0010}, // 乙烯
            "C3H6": {t0: 0.1381, t15: 0.1267, t15_55: 0.1263, t20: 0.1232, u: 0.0016}, // 丙烯
            "C4H8": {t0: 0.1964, t15: 0.1776, t15_55: 0.1770, t20: 0.1721, u: 0.0041}, // 丁烯
            "C5H10": {t0: 0.2622, t15: 0.2297, t15_55: 0.2287, t20: 0.2208, u: 0.0102}, // 戊烯
            "He": {t0: -0.01, t15: -0.01, t15_55: -0.01, t20: -0.01, u: 0.025},
            "Ar": {t0: 0.0307, t15: 0.0273, t15_55: 0.0272, t20: 0.0262, u: 0.0010},
            "N2": {t0: 0.0215, t15: 0.0170, t15_55: 0.0169, t20: 0.0156, u: 0.0010},
            "CO2": {t0: 0.0821, t15: 0.0752, t15_55: 0.0749, t20: 0.0730, u: 0.0020},
            "H2O": {t0: 0.3093, t15: 0.2562, t15_55: 0.2546, t20: 0.2419, u: 0.0150},
            "H2S": {t0: 0.1006, t15: 0.0923, t15_55: 0.0920, t20: 0.0898, u: 0.0023},
            "H2": {t0: -0.01, t15: -0.01, t15_55: -0.01, t20: -0.01, u: 0.025},
            "Ne": {t0: -0.01, t15: -0.01, t15_55: -0.01, t20: -0.01, u: 0.025}, // 氖气
            "CO": {t0: 0.0258, t15: 0.0217, t15_55: 0.0215, t20: 0.0203, u: 0.0010},
            "O2": {t0: 0.0311, t15: 0.0276, t15_55: 0.0275, t20: 0.0265, u: 0.0010},
        }
    }
}


function 燃气摩尔密度(压力, 温度, 压缩因子) {
    if (温度 > 273.15) {
        温度 = 温度 - 273.15;
    }
    return 压力 / 压缩因子 / 0.00831451 / (温度 + 273.15);
}


function 摩尔质量_燃气(组分体积分数数组) {
    let p_compo = 组分体积分数数组.Value2;
    let p_compo_arr = [];
    if (p_compo[0][0] > 1) {
        for (let i = 0; i < p_compo.length; i++) {
            p_compo_arr[i] = p_compo[i][0] / 100;
        }
    }
    M_mole = [16.043, 28.0135, 44.01, 30.07, 44.097, // 甲烷、氮气、二氧化碳、乙烷、丙烷
        18.0153, 34.082, 2.0159, 28.01, 31.9988, // 水、硫化氢、氢气、一氧化碳、氧气
        58.123, 58.123, 72.15, 72.15, 86.177,   // 异丁烷、正丁烷、异戊烷、正戊烷、己烷
        100.204, 114.231, 128.258, 142.285, 4.0026, // 庚烷、辛烷、壬烷、癸烷、氦气
        39.948, 28.05376, 42.08064, 56.10752, 70.1344]  // 氩气、乙烯、丙烯、丁烯、戊烯，本行分子量来自于余热锅炉规程，其他的来自于燃气轮机规程

    if (M_mole.length !== p_compo_arr.length) {
        return "组分数组长度错误"
    }
    let sum = 0;
    for (let i = 0; i < p_compo_arr.length; i++) {
        sum = sum + M_mole[i] * p_compo_arr[i];
    }
    return sum;
}

function 摩尔流量变化(组分名, 燃气摩尔流量, 组分体积分数数组) {
    // 燃烧产物相对于进口空气摩尔流量的组分摩尔流量变化
    // 组分名可取值："CO2","O2","N2","Ar","H2O","SO2"
    // 组分体积分数数组的组分顺序为：甲烷、氮气、二氧化碳、乙烷、丙烷、水、硫化氢、氢气、一氧化碳、氧气
    // 异丁烷、正丁烷、异戊烷、正戊烷、己烷、庚烷、辛烷、壬烷、癸烷、氦气、氩气、乙烯、丙烯,丁烯，戊烯
    let p_compo = 组分体积分数数组.Value2;
    let p_compo_arr = [];
    if (p_compo[0][0] > 1) {
        for (let i = 0; i < p_compo.length; i++) {
            p_compo_arr.push(p_compo[i][0] / 100);
        }
    }
    if (p_compo_arr.length !== 25) {
        return "组分不全"
    }
    let change = [];
    let c = 常量().combustion_ratios[组分名];
    change = [c.CH4, c.N2, c.CO2, c.C2H6, c.C3H8,
        c.H2O, c.H2S, c.H2, c.CO, c.O2,
        c.C4H10, c.C4H10, c.C5H12, c.C5H12, c.C6H14,
        c.C7H16, c.C8H18, c.C9H20, c.C10H22, c.He,
        c.Ar, c.C2H4, c.C3H6, c.C4H8, c.C5H10]

    let sum = 0;
    for (let i = 0; i < p_compo_arr.length; i++) {
        sum = sum + p_compo_arr[i] * change[i];
    }
    return sum * 燃气摩尔流量;
}

function 燃烧所需干空气质量流量(燃气摩尔流量_kmol_h, 组分体积分数数组) {
    // 组分体积分数数组即燃料气的组分报告，体积分数=摩尔分数
    //
    if (!燃气摩尔流量_kmol_h) {
        return 0;
    }
    let _tmp = 摩尔流量变化("O2", 燃气摩尔流量_kmol_h, 组分体积分数数组);
    if (typeof _tmp === "string") {
        return _tmp;
    }
    let 燃气燃烧所需氧气的摩尔流量 = Math.abs(_tmp);
    let 燃气燃烧所需干空气的摩尔流量 = 燃气燃烧所需氧气的摩尔流量 / 常量().干空气组分.摩尔分数.O2;
    let 燃气燃烧所需干空气的质量流量 = 燃气燃烧所需干空气的摩尔流量 * 常量().干空气摩尔质量;  // 此处干空气的分子量与余热锅炉规程不同
    return 燃气燃烧所需干空气的质量流量;
}

function 燃烧所需湿空气质量流量(空气含湿量, 燃气摩尔流量_kmol_h, 组分体积分数数组) {
    let 干空气质量流量 = 燃烧所需干空气质量流量(燃气摩尔流量_kmol_h, 组分体积分数数组);
    return 干空气质量流量 * (1 + 空气含湿量);
}

function 燃烧产物摩尔流量(组分名, 干空气分数, 燃烧所需湿空气质量流量_kg_h, 燃料质量流量_kg_h, 燃气组分体积分数数组, 注入流量_opt,
                  摩尔质量_燃气_opt,
                  摩尔质量_湿空气_opt) {
    // 组分名：N2, O2, CO2, H2O, Ar, SO2
    // 干空气分数：即燃机所处环境空气的干空气分数，为体积分数或摩尔分数
    // 燃烧所需湿空气质量流量，kg/h

    if (!注入流量_opt) {
        注入流量_opt = 0;
    }

    let mass_mole_gas = 摩尔质量_燃气_opt;
    if (!mass_mole_gas) {
        mass_mole_gas = 摩尔质量_燃气(燃气组分体积分数数组);
    }
    let flow_mole_gas = 燃料质量流量_kg_h / mass_mole_gas;

    // 摩尔质量
    let mass_mole_humid_air = 摩尔质量_湿空气_opt;
    if (!mass_mole_humid_air) {
        mass_mole_humid_air = 摩尔质量_湿空气(干空气分数);
    }

    // 湿空气摩尔流量
    let flow_mole_humid_air = 燃烧所需湿空气质量流量_kg_h / mass_mole_humid_air;
    let flow_mole_comp = flow_mole_humid_air * 摩尔分数_湿空气组分(组分名, 干空气分数);

    // 燃烧摩尔变化
    let delta_comp = 摩尔流量变化(组分名, flow_mole_gas, 燃气组分体积分数数组);
    if (组分名 === "H2O") {  // 组分为水时需要特殊处理
        delta_comp = delta_comp + 注入流量_opt / 常量().分子量.H2O;
    }

    // 燃机排汽质量分数
    let result = flow_mole_comp + delta_comp;
    if (!result)
        if (result === 0) {
            return 0;
        } else {
            return "组分不全或组分名错误";
        }
    return result;
}


function 燃烧产物质量分数(组分名, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt) {
    // 组分名：N2, O2, CO2, H2O, Ar, SO2
    // 干空气分数：即燃机所处环境空气的干空气分数，为体积分数或摩尔分数
    // 燃烧所需湿空气质量流量，kg/h

    if (!注入流量_opt) {
        注入流量_opt = 0;
    }

    let mass_flow_total = 燃烧所需湿空气质量流量 + 燃料质量流量 + 注入流量_opt;

    // 燃机排汽质量分数
    let result = 燃烧产物摩尔流量(组分名, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt) *
        常量().分子量[组分名] / mass_flow_total;
    if (result) {
        return result
    } else {
        if (result === 0) {
            return 0;
        }
        return "组分不全或组分名错误";
    }

}

function 焓_组分(组分名, 温度_K, 基准温度_K) {
    if (基准温度_K === undefined || 基准温度_K + 0 !== 基准温度_K) { // 如果有另一个函数调用，则基准温度_K可能为空的number类型，则满足第二个条件
        基准温度_K = 288.15;
    }
    let R = 8.31451;
    let F = new Array(11);
    if (组分名 === "N2") {
        F[1] = 22103.715
        F[2] = -381.84618
        F[3] = 6.08273836
        F[4] = -0.008530914
        F[5] = 0.0000138465
        F[6] = -0.00000000962579
        F[7] = 2.51971E-12
        F[8] = 710.846086
        F[9] = 0
        F[10] = 28.0134
    } else if (组分名 === "O2") {
        F[1] = -34255.6342
        F[2] = 484.700097
        F[3] = 1.11901096
        F[4] = 0.004293889
        F[5] = -0.00000068363
        F[6] = -0.00000000202337
        F[7] = 1.03904E-12
        F[8] = -3391.4549
        F[9] = 0
        F[10] = 31.9988
    } else if (组分名 === "CO2") {
        F[1] = 49436.5054
        F[2] = -626.411601
        F[3] = 5.30172524
        F[4] = 0.002503814
        F[5] = -0.00000021273
        F[6] = -0.000000000768999
        F[7] = 2.84968E-13
        F[8] = -45281.9846
        F[9] = -393510
        F[10] = 44.0095
    } else if (组分名 === "H2O") {
        F[1] = -39479.6083
        F[2] = 575.573102
        F[3] = 0.931782653
        F[4] = 0.007222713
        F[5] = -0.00000734256
        F[6] = 0.00000000495504
        F[7] = -1.33693E-12
        F[8] = -33039.7431
        F[9] = -241826
        F[10] = 18.0153
    } else if (组分名 === "Ar") {
        F[1] = 0
        F[2] = 0
        F[3] = 2.5
        F[4] = 0
        F[5] = 0
        F[6] = 0
        F[7] = 0
        F[8] = -745.375
        F[9] = 0
        F[10] = 39.948
    } else if (组分名 === "SO2") {
        F[1] = -53108.4214
        F[2] = 909.031167
        F[3] = -2.356891244
        F[4] = 0.0220445
        F[5] = -0.0000251078
        F[6] = 0.000000014463
        F[7] = -3.36907E-12
        F[8] = -41137.5212
        F[9] = -296810
        F[10] = 64.0638
    } else if (组分名 === "CO") {
        F[1] = 14890.45326
        F[2] = -292.2285939
        F[3] = 5.72452717
        F[4] = -0.008176235
        F[5] = 0.000014569
        F[6] = -0.0000000108775
        F[7] = 3.02794E-12
        F[8] = -13031.31878
        F[9] = -110535.196
        F[10] = 28.0101
    } else if (组分名 === "H2S") {
        F[1] = 9543.80881
        F[2] = -68.7517508
        F[3] = 4.05492196
        F[4] = -0.000301456
        F[5] = 0.0000037685
        F[6] = -0.00000000223936
        F[7] = 3.08686E-13
        F[8] = -3278.45728
        F[9] = -20600
        F[10] = 34.0809
    } else if (组分名 === "H2") {
        F[1] = 40783.2321
        F[2] = -800.918604
        F[3] = 8.21470201
        F[4] = -0.012697145
        F[5] = 0.0000175361
        F[6] = -0.0000000120286
        F[7] = 3.36809E-12
        F[8] = 2682.484665
        F[9] = 0
        F[10] = 2.0159
    } else if (组分名 === "He") {
        F[1] = 0
        F[2] = 0
        F[3] = 2.5
        F[4] = 0
        F[5] = 0
        F[6] = 0
        F[7] = 0
        F[8] = 745.375
        F[9] = 0
        F[10] = 4.0026
    } else if (组分名 === "CH4") {
        F[1] = -176685.0998
        F[2] = 2786.18102
        F[3] = -12.0257785
        F[4] = 0.039176193
        F[5] = -0.0000361905
        F[6] = 0.0000000202685
        F[7] = -4.97671E-12
        F[8] = -23313.1436
        F[9] = -74600
        F[10] = 16.0425
    } else if (组分名 === "C2H6") {
        F[1] = -186204.4161
        F[2] = 3406.19186
        F[3] = -19.51705092
        F[4] = 0.075658356
        F[5] = -0.0000820417
        F[6] = 0.0000000506114
        F[7] = -1.31928E-11
        F[8] = -27029.3289
        F[9] = -83851.544
        F[10] = 30.069
    } else if (组分名 === "C3H8") {
        F[1] = -243314.4337
        F[2] = 4656.27081
        F[3] = -29.39466091
        F[4] = 0.118895275
        F[5] = -0.000137631
        F[6] = 0.0000000881482
        F[7] = -2.34299E-11
        F[8] = -35403.3527
        F[9] = -104680
        F[10] = 44.0956
    } else if (组分名 === "C4H10iso") {
        F[1] = -383446.933
        F[2] = 7000.03964
        F[3] = -44.400269
        F[4] = 0.174618345
        F[5] = -0.00020782
        F[6] = 0.000000133979
        F[7] = -3.55168E-11
        F[8] = -50340.1889
        F[9] = -134990
        F[10] = 58.1222
    } else if (组分名 === "C4H10n") {
        F[1] = -317587.254
        F[2] = 6176.33182
        F[3] = -38.9156212
        F[4] = 0.158465428
        F[5] = -0.000186005
        F[6] = 0.000000119968
        F[7] = -3.20167E-11
        F[8] = -45403.6339
        F[9] = -125790
        F[10] = 58.1222
    } else if (组分名 === "C5H12iso") {
        F[1] = -423190.339
        F[2] = 6497.1891
        F[3] = -36.8112697
        F[4] = 0.153242473
        F[5] = -0.000154879
        F[6] = 0.000000087499
        F[7] = -2.07055E-11
        F[8] = -51554.1659
        F[9] = -153700
        F[10] = 72.1488
    } else if (组分名 === "C5H12n") {
        F[1] = -276889.4625
        F[2] = 5834.28347
        F[3] = -36.1754148
        F[4] = 0.153333971
        F[5] = -0.00015284
        F[6] = 0.0000000819109
        F[7] = -1.79233E-11
        F[8] = -46653.7525
        F[9] = -146760
        F[10] = 72.1488
    } else if (组分名 === "C6H14n") {
        F[1] = -581592.67
        F[2] = 10790.97724
        F[3] = -66.3394703
        F[4] = 0.252371516
        F[5] = -0.000290434
        F[6] = 0.00000018022
        F[7] = -4.61722E-11
        F[8] = -72715.4457
        F[9] = -166920
        F[10] = 86.1754
    }

    let H = ((-F[1] / 温度_K + F[2] * Math.log(温度_K) + F[3] * 温度_K + F[4] * 温度_K * 温度_K / 2 + F[5] * Math.pow(温度_K, 3) / 3
        + F[6] * Math.pow(温度_K, 4) / 4 + F[7] * Math.pow(温度_K, 5) / 5 + F[8]) * R - F[9]) / F[10] / 2.326;
    let Hr = ((-F[1] / 基准温度_K + F[2] * Math.log(基准温度_K) + F[3] * 基准温度_K + F[4] * 基准温度_K * 基准温度_K / 2
        + F[5] * Math.pow(基准温度_K, 3) / 3
        + F[6] * Math.pow(基准温度_K, 4) / 4 + F[7] * Math.pow(基准温度_K, 5) / 5 + F[8]) * R - F[9]) / F[10] / 2.326;
    return 2.326 * (H - Hr);
}

function 显热_燃气(温度, 组分体积分数数组, 基准温度_opt) {
    let 基准温度_K;
    if (!基准温度_opt) {
        基准温度_K = 288.15;
    } else {
        基准温度_K = 基准温度_opt + 273.15;
    }
    let 温度_K = 温度 + 273.15;
    let p_compo = 组分体积分数数组.Value2;
    let p_compo_arr = {};
    let 组分名 = 常量().组分名列表;
    if (p_compo[0][0] > 1) {
        for (let i = 0; i < p_compo.length; i++) {
            p_compo_arr[组分名[i]] = p_compo[i][0] / 100;
        }
    }

    for (let i = 0; i < 组分名.length; i++) {
        let h = 焓_组分(组分名[i], 温度_K)
    }
}

function 焓_燃烧产物_余热锅炉进出口(进口或出口温度, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt, 基准温度_opt) {
    // 此处的燃烧产物不考虑平衡湿空气
    // 余热锅炉进口即燃机排气
    let 基准温度_K;
    if (!基准温度_opt) {
        基准温度_K = 288.15;
    } else {
        基准温度_K = 基准温度_opt + 273.15;
    }
    let 温度_K = 进口或出口温度 + 273.15;

    // 获取烟气中各种组分的质量分数
    let mass_frac_N2 = 燃烧产物质量分数("N2", 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt);
    let mass_frac_O2 = 燃烧产物质量分数("O2", 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt);
    let mass_frac_CO2 = 燃烧产物质量分数("CO2", 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt);
    let mass_frac_H2O = 燃烧产物质量分数("H2O", 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt);
    let mass_frac_SO2 = 燃烧产物质量分数("SO2", 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt);
    let mass_frac_Ar = 燃烧产物质量分数("Ar", 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt);

    // 获取烟气中各种组分的焓
    let h_N2 = 焓_组分("N2", 温度_K, 基准温度_K);
    let h_O2 = 焓_组分("O2", 温度_K, 基准温度_K);
    let h_CO2 = 焓_组分("CO2", 温度_K, 基准温度_K);
    let h_H2O = 焓_组分("H2O", 温度_K, 基准温度_K);
    let h_SO2 = 焓_组分("SO2", 温度_K, 基准温度_K);
    let h_Ar = 焓_组分("Ar", 温度_K, 基准温度_K);

    return mass_frac_N2 * h_N2 + mass_frac_O2 * h_O2 + mass_frac_CO2 * h_CO2 + mass_frac_H2O * h_H2O
        + mass_frac_SO2 * h_SO2 + mass_frac_Ar * h_Ar;
}


function 平衡空气流量_余热锅炉热平衡(HRSG进口平衡空气焓, HRSG出口平衡空气焓, HRSG进口燃烧产物焓, HRSG出口燃烧产物焓, 燃烧产物质量流量, HRSG热负荷) {
    /**
     * HRSG平衡空气即燃机进口空气扣除燃烧必须的空气后富余的空气
     * HRSG燃烧产物即燃气和其燃烧必须的空气燃烧后的产物，不包括平衡空气量
     * HRSG热负荷即余热锅炉传递给汽水循环中的总热量
     */
    let 分子 = HRSG热负荷 + (0.0015 - 1) * 燃烧产物质量流量 * HRSG进口燃烧产物焓 + 燃烧产物质量流量 * HRSG出口燃烧产物焓;
    let 分母 = (1 - 0.0015) * HRSG进口平衡空气焓 - HRSG出口平衡空气焓;
    return 分子 / 分母;
}

function 燃机排气质量分数(组分名, 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt) {
    if (!注入流量_opt) {
        注入流量_opt = 0;
    }

    // 燃烧产物摩尔流量
    let flow_mole_N2_to = 燃烧产物摩尔流量("N2", 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt);
    let flow_mole_O2_to = 燃烧产物摩尔流量("O2", 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt);
    let flow_mole_CO2_to = 燃烧产物摩尔流量("CO2", 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt);
    let flow_mole_H2O_to = 燃烧产物摩尔流量("H2O", 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt);
    let flow_mole_Ar_to = 燃烧产物摩尔流量("Ar", 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt);
    let flow_mole_SO2_to = 燃烧产物摩尔流量("SO2", 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt);

    let mass_mole_humid_air = 摩尔质量_湿空气(干空气分数);
    let flow_mole_humid_air = 平衡空气质量流量 / mass_mole_humid_air;
    let flow_mass_all = 平衡空气质量流量 + 燃料质量流量 + 燃烧所需湿空气质量流量 + 注入流量_opt;

    // 湿空气摩尔分数
    let frac_mole_N2_wet = 摩尔分数_湿空气("N2", 干空气分数);
    let frac_mole_O2_wet = 摩尔分数_湿空气("O2", 干空气分数);
    let frac_mole_CO2_wet = 摩尔分数_湿空气("CO2", 干空气分数);
    let frac_mole_H2O_wet = 摩尔分数_湿空气("H2O", 干空气分数);
    let frac_mole_Ar_wet = 摩尔分数_湿空气("Ar", 干空气分数);

    // 平衡空气摩尔流量
    let flow_mole_N2_wa = flow_mole_humid_air * frac_mole_N2_wet;
    let flow_mole_O2_wa = flow_mole_humid_air * frac_mole_O2_wet;
    let flow_mole_CO2_wa = flow_mole_humid_air * frac_mole_CO2_wet;
    let flow_mole_H2O_wa = flow_mole_humid_air * frac_mole_H2O_wet;
    let flow_mole_Ar_wa = flow_mole_humid_air * frac_mole_Ar_wet;

    // 燃机排汽摩尔流量
    let flow_mole_N2 = flow_mole_N2_wa + flow_mole_N2_to;
    let flow_mole_O2 = flow_mole_O2_wa + flow_mole_O2_to;
    let flow_mole_CO2 = flow_mole_CO2_wa + flow_mole_CO2_to;
    let flow_mole_H2O = flow_mole_H2O_wa + flow_mole_H2O_to;
    let flow_mole_Ar = flow_mole_Ar_wa + flow_mole_Ar_to;
    let flow_mole_SO2 = flow_mole_SO2_to;

    // 燃机排气质量分数
    if (组分名 === "N2") {
        return 28.0135 * flow_mole_N2 / flow_mass_all;
    } else if (组分名 === "O2") {
        return 31.9988 * flow_mole_O2 / flow_mass_all;
    } else if (组分名 === "CO2") {
        return 44.01 * flow_mole_CO2 / flow_mass_all;
    } else if (组分名 === "H2O") {
        return 18.0153 * flow_mole_H2O / flow_mass_all;
    } else if (组分名 === "Ar") {
        return 39.948 * flow_mole_Ar / flow_mass_all;
    } else if (组分名 === "SO2") {
        return 64.0638 * flow_mole_SO2 / flow_mass_all;
    }
}

function 焓_烟气(烟气温度, 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt, 基准温度_opt) {
    // 考虑平衡湿空气时余热锅炉各处的烟气焓
    if (!注入流量_opt) {
        注入流量_opt = 0;
    }
    if (!基准温度_opt) {
        基准温度_opt = 15;
    }
    let frac_mass_N2 = 燃机排气质量分数("N2", 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt);
    let frac_mass_O2 = 燃机排气质量分数("O2", 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
    let frac_mass_CO2 = 燃机排气质量分数("CO2", 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
    let frac_mass_H2O = 燃机排气质量分数("H2O", 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
    let frac_mass_Ar = 燃机排气质量分数("Ar", 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)
    let frac_mass_SO2 = 燃机排气质量分数("SO2", 平衡空气质量流量, 干空气分数, 燃烧所需湿空气质量流量, 燃料质量流量, 燃气组分体积分数数组, 注入流量_opt)

    // 组分焓
    let h_N2 = 焓_组分("N2", 烟气温度 + 273.15, 基准温度_opt + 273.15);
    let h_O2 = 焓_组分("O2", 烟气温度 + 273.15, 基准温度_opt + 273.15);
    let h_CO2 = 焓_组分("CO2", 烟气温度 + 273.15, 基准温度_opt + 273.15);
    let h_H2O = 焓_组分("H2O", 烟气温度 + 273.15, 基准温度_opt + 273.15);
    let h_Ar = 焓_组分("Ar", 烟气温度 + 273.15, 基准温度_opt + 273.15);
    let h_SO2 = 焓_组分("SO2", 烟气温度 + 273.15, 基准温度_opt + 273.15);

    return frac_mass_N2 * h_N2 + frac_mass_O2 * h_O2 + frac_mass_CO2 * h_CO2 + frac_mass_H2O * h_H2O + frac_mass_Ar * h_Ar + frac_mass_SO2 * h_SO2;
}

function _get_arr_of_range(xx) {
    /**
     * 从et选择的区域中拿到相应的数据数组
     */
    let p_compo = xx.Value2;
    let p_compo_arr = [];
    if (p_compo[0][0] > 1) {
        for (let i = 0; i < p_compo.length; i++) {
            p_compo_arr.push(p_compo[i][0] / 100);
        }
    }
    return p_compo_arr;
}

function 压缩因子_ex(压力_kPa, 温度, 组分体积分数数组, 基准温度_opt) {
    /**
     * 参考《GB/T 11062 天然气发热量、密度、相对密度和沃泊指数的计算方法》
     * 温度：℃
     * 基准温度_opt:可选参数，℃
     */
    let p0 = 101.325; // 基准压力
    let t0 = 15;
    if (基准温度_opt) {
        t0 = 基准温度_opt;
    }
    let t_index;
    if (t0 === 15.55) {
        t_index = "t15_55";
    } else {
        t_index = "t" + t0;
    }
    let p_compo_arr = _get_arr_of_range(组分体积分数数组);
    if (p_compo_arr.length !== 25) {
        return "组分不全"
    }
    let sigma = 0;
    let 组分名列表 = 常量().组分名列表;
    for (let i = 0; i < 组分名列表.length; i++) {
        let 组分名 = 组分名列表[i];
        try {
            sigma = sigma + p_compo_arr[i] * 常量().压缩因子[组分名][t_index];
        } catch (e) {
            return "计算组分" + 组分名 + "时出错"
        }
    }
    return 1 - 压力_kPa / p0 * sigma * sigma;
}


function 压缩因子(压力_MPa, 温度_K, 组分体积分数数组) {
    // 定义迭代变量：n,i,j
    // NN:天然气组分数，NN=21
    if (温度_K < 230) {
        温度_K = 温度_K + 273.15;
    }
    // 定义气体常数，R=0.00831451 MJ/(kmol*K)
    let R = 0.00831451;

    // 将输入区域给天然气摩尔组分数组赋值
    let p_compo = 组分体积分数数组.Value2;
    let p_compo_arr = [];
    if (p_compo[0][0] > 1) {
        for (let i = 0; i < p_compo.length; i++) {
            p_compo_arr[i] = p_compo[i][0] / 100;
        }
    }
    if (p_compo_arr.length !== 21) {
        return "组分不全"
    }

    // *****************************************************************************************************************
    let a = [0, 0.1538326, 1.341953, -2.998583, -0.04831228, 0.3757965, -1.589575, -0.05358847, 0.88659463, -0.71023704, -1.471722, 1.32185035, -0.78665925,
        0.00000000229129, 0.1576724, -0.4363864, -0.04408159, -0.003433888, 0.03205905, 0.02487355, 0.07332279, -0.001600573, 0.6424706, -0.4162601,
        -0.06689957, 0.2791795, -0.6966051, -0.002860589, -0.008098836, 3.150547, 0.007224479, -0.7057529, 0.5349792, -0.07931491, -1.418465, -5.99905E-17,
        0.1058402, 0.03431729, -0.007022847, 0.02495587, 0.04296818, 0.7465453, -0.2919613, 7.294616, -9.936757, -0.005399808, -0.2432567, 0.04987016,
        0.003733797, 1.874951, 0.002168144, -0.6587164, 0.000205518, 0.009776195, -0.02048708, 0.01557322, 0.006862415, -0.001226752, 0.002850908];
    let B = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
        5, 5, 6, 6, 7, 7, 8, 8, 8, 9, 9];
    let C = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1,
        1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1];
    let K = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 4, 4, 0, 0, 2, 2, 2, 4, 4, 4, 4, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 0, 0, 2, 2, 2, 4, 4, 0, 2, 2,
        4, 4, 0, 2, 0, 2, 1, 2, 2, 2, 2];
    let U = [0, 0, 0.5, 1, 3.5, -0.5, 4.5, 0.5, 7.5, 9.5, 6, 12, 12.5, -6, 2, 3, 2, 2, 11, -0.5, 0.5, 0, 4, 6, 21, 23, 22, -1, -0.5, 7, -1, 6, 4, 1, 9, -13,
        21, 8, -0.5, 0, 2, 7, 9, 22, 23, 1, 9, 3, 8, 23, 1.5, 5, -0.5, 4, 7, 3, 0, 1, 0];
    let G = [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0];
    let Q = [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
        0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1];
    let F = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    let S = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    let W = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    // 摩尔质量
    let MW = [0, 16.043, 28.0135, 44.01, 30.07,
        44.097, 18.0153, 34.082, 2.0159, 28.01,
        31.9988, 58.123, 58.123, 72.15, 72.15,
        86.177, 100.204, 114.231, 128.258, 142.285,
        4.0026, 39.948];
    let EI = [0, 151.3183, 99.73778, 241.9606, 244.1667, 298.1183, 514.0156, 296.355, 26.95794, 105.5348, 122.7667, 324.0689, 337.6389, 365.5999, 370.6823,
        402.636293, 427.72263, 450.325022, 470.840891, 489.558373, 2.610111, 119.6299];
    let KI = [0, 0.4619255, 0.4479153, 0.4557489, 0.5279209, 0.583749, 0.3825868, 0.4618263, 0.3514916, 0.4533894, 0.4186954, 0.6406937, 0.6341423, 0.6738577,
        0.6798307, 0.7175118, 0.7525189, 0.784955, 0.8152731, 0.8437826, 0.3589888, 0.4216551];
    let GI = [0, 0, 0.027815, 0.189065, 0.0793, 0.141239, 0.3325, 0.0885, 0.034369, 0.038953, 0.021, 0.256692, 0.281835, 0.332267, 0.366911, 0.289731, 0.337542,
        0.383381, 0.427354, 0.469659, 0, 0];
    let QI = [0, 0, 0, 0.69, 0, 0, 1.06775, 0.633276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    let FI = [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    let SI = [0, 0, 0, 0, 0, 0, 1.5822, 0.39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    let WI = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    // 给EIJ赋初值
    let EIJ = [[1, 0.97164, 0.960644, 1, 0.994635, 0.708218, 0.931484, 1.17052, 0.990126, 1, 1.01953, 0.989844, 1.00235, 0.999268, 1.107274, 0.88088, 0.880973, 0.881067, 0.881161, 1, 1],
        [0.97164, 1, 1.02274, 0.97012, 0.945939, 0.746954, 0.902271, 1.08632, 1.00571, 1.021, 0.946914, 0.973384, 0.95934, 0.94552, 1, 1, 1, 1, 1, 1, 1],
        [0.960644, 1.02274, 1, 0.925053, 0.960237, 0.849408, 0.955052, 1.28179, 1.5, 1, 0.906849, 0.897362, 0.726255, 0.859764, 0.855134, 0.831229, 0.80831, 0.786323, 0.765171, 1, 1],
        [1, 0.97012, 0.925053, 1, 1.02256, 0.693168, 0.946871, 1.16446, 1, 1, 1, 1.01306, 1, 1.00532, 1, 1, 1, 1, 1, 1, 1],
        [0.994635, 0.945939, 0.960237, 1.02256, 1, 1, 1, 1.034787, 1, 1, 1, 1.0049, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.708218, 0.746954, 0.849408, 0.693168, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.931484, 0.902271, 0.955052, 0.946871, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.008692, 1.010126, 1.011501, 1.012821, 1.014089, 1, 1],
        [1.17052, 1.08632, 1.28179, 1.16446, 1.034787, 1, 1, 1, 1.1, 1, 1.3, 1.3, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.990126, 1.00571, 1.5, 1, 1, 1, 1, 1.1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1.021, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1.01953, 0.946914, 0.906849, 1, 1, 1, 1, 1.3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.989844, 0.973384, 0.897362, 1.01306, 1.0049, 1, 1, 1.3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1.00235, 0.95934, 0.726255, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.999268, 0.94552, 0.859764, 1.00532, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1.107274, 1, 0.855134, 1, 1, 1, 1.008692, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.88088, 1, 0.831229, 1, 1, 1, 1.010126, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.880973, 1, 0.80831, 1, 1, 1, 1.011501, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.881067, 1, 0.786323, 1, 1, 1, 1.012821, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.881161, 1, 0.765171, 1, 1, 1, 1.014089, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]];

    EIJ = transpose(EIJ);
    // 给UIJ赋初值
    let UIJ = [[1, 0.886106, 0.963827, 1, 0.990877, 1, 0.736833, 1.15639, 1, 1, 1, 0.992291, 1, 1.00367, 1.302576, 1.191904, 1.205769, 1.219634, 1.233498, 1, 1],
        [0.886106, 1, 0.835058, 0.816431, 0.915502, 1, 0.993476, 0.408838, 1, 1, 1, 0.993556, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.963827, 0.835058, 1, 0.96987, 1, 1, 1.04529, 1, 0.9, 1, 1, 1, 1, 1, 1.066638, 1.077634, 1.088178, 1.098291, 1.108021, 1, 1],
        [1, 0.816431, 0.96987, 1, 1.065173, 1, 0.971926, 1.61666, 1, 1, 1.25, 1.25, 1.25, 1.25, 1, 1, 1, 1, 1, 1, 1],
        [0.990877, 0.915502, 1, 1.065173, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.736833, 0.993476, 1.04529, 0.971926, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.028973, 1.033754, 1.038338, 1.042735, 1.046966, 1, 1],
        [1.15639, 0.408838, 1, 1.61666, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 0.9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1.25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.992291, 0.993556, 1, 1.25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1.25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1.00367, 1, 1, 1.25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1.302576, 1, 1.066638, 1, 1, 1, 1.028973, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1.191904, 1, 1.077634, 1, 1, 1, 1.033754, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1.205769, 1, 1.088178, 1, 1, 1, 1.038338, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1.219634, 1, 1.098291, 1, 1, 1, 1.042735, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1.233498, 1, 1.108021, 1, 1, 1, 1.046966, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]];

    UIJ = transpose(UIJ);

    // 给KIJ赋初值
    let KIJ = [[1, 1.00363, 0.995933, 1, 1.007619, 1, 1.00008, 1.02326, 1, 1, 1, 0.997596, 1, 1.002529, 0.982962, 0.983565, 0.982707, 0.981849, 0.980991, 1, 1],
        [1.00363, 1, 0.982361, 1.00796, 1, 1, 0.942596, 1.03227, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.995933, 0.982361, 1, 1.00851, 1, 1, 1.00779, 1, 1, 1, 1, 1, 1, 1, 0.910183, 0.895362, 0.881152, 0.86752, 0.854406, 1, 1],
        [1, 1.00796, 1.00851, 1, 0.986893, 1, 0.999969, 1.02034, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1.007619, 1, 1, 0.986893, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1.00008, 0.942596, 1.00779, 0.999969, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.96813, 0.96287, 0.957828, 0.952441, 0.948338, 1, 1],
        [1.02326, 1.03227, 1, 1.02034, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.997596, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1.002529, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.982962, 1, 0.910183, 1, 1, 1, 0.96813, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.983565, 1, 0.895362, 1, 1, 1, 0.96287, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.982707, 1, 0.881152, 1, 1, 1, 0.957828, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.981849, 1, 0.86752, 1, 1, 1, 0.952441, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.980991, 1, 0.854406, 1, 1, 1, 0.948338, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]

    KIJ = transpose(KIJ);

    // 给GIJ赋初值
    let GIJ = [[1, 1, 0.807653, 1, 1, 1, 1, 1.95731, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 0.982746, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0.807653, 0.982746, 1, 0.370296, 1, 1.67309, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 0.370296, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1.67309, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1.95731, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]

    GIJ = transpose(GIJ);

    //******************************************************************************************************************
    // 摩尔分数标准化
    let XI = p_compo_arr;
    XI = [0].concat(XI);
    // 计算平均摩尔质量
    let MWX = 摩尔质量_燃气(组分体积分数数组);
    // ***************************************************计算第二维里系数*************************************************
    let BI = new Array(19);
    let K1 = 0;
    let U1 = 0;
    let G1 = 0;
    let Q1 = 0;
    let F1 = 0;
    let E1 = 0;
    for (let i = 1; i < 22; i++) {
        K1 = K1 + XI[i] * Math.pow(KI[i], 2.5);
        U1 = U1 + XI[i] * Math.pow(EI[i], 2.5);
        G1 = G1 + XI[i] * GI[i];
        Q1 = Q1 + XI[i] * QI[i];
        F1 = F1 + XI[i] * XI[i] * FI[i];
        E1 = E1 + XI[i] * EI[i];
    }

    // '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    K1 = K1 * K1;
    U1 = U1 * U1;
    for (let i = 1; i < 21; i++) {
        for (let j = i + 1; j < 22; j++) {
            let XIJ = XI[i] * XI[j];
            if (XIJ !== 0) {
                K1 = K1 + 2 * XIJ * (Math.pow(KIJ[i - 1][j - 1], 5) - 1) * Math.pow(KI[i] * KI[j], 2.5)
                U1 = U1 + 2 * XIJ * (Math.pow(UIJ[i - 1][j - 1], 5) - 1) * Math.pow(EI[i] * EI[j], 2.5)
                G1 = G1 + XIJ * (GIJ[i - 1][j - 1] - 1) * (GI[i] + GI[j])
            }
        }
    }

    K1 = Math.pow(K1, 0.2);
    U1 = Math.pow(U1, 0.2);

    // '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    for (let n = 1; n <= 18; n++) {
        let BBN = 0;
        for (let i = 1; i <= 21; i++) {
            for (let j = 1; j <= 21; j++) {
                let XIJ = XI[i] * XI[j];
                let EIJ0 = EIJ[i - 1][j - 1] * Math.pow((EI[i] * EI[j]), 0.5)
                let GIJ0 = GIJ[i - 1][j - 1] * (GI[i] + GI[j]) / 2

                let BN = Math.pow(GIJ0 + 1 - G[n], (G[n]))
                    * Math.pow(QI[i] * QI[j] + 1 - Q[n], Q[n])
                    * Math.pow(Math.pow(FI[i], 0.5) * Math.pow(FI[j], 0.5) + 1 - F[n], F[n])
                    * Math.pow(SI[i] * SI[j] + 1 - S[n], S[n])
                    * Math.pow(WI[i] * WI[j] + 1 - W[n], W[n])

                BBN = BBN + XIJ * Math.pow(EIJ0, U[n]) * Math.pow(KI[i] * KI[j], 1.5) * BN
            }
        }
        BI[n] = a[n] * BBN
    }

    let CNS = [];
    // ************************************************求解系数CN********************************************************
    for (let n = 13; n <= 58; n++) {
        CNS[n] = Math.pow(G1 + 1 - G[n], G[n]) * Math.pow((Math.pow(Q1, 2) + 1 - Q[n]), Q[n])
            * Math.pow((F1 + 1 - F[n]), F[n]) * a[n] * Math.pow(U1, U[n]);
    }
    // *********************************************开始循环求解**********************************************************

    // Dim D_unknown, Z, BMIX As Double
    let TOL = 0.5 * Math.pow(10, -9)
    let X1 = 0.000001
    let X2 = 40
    let D_unknown = 0;
    let Z;
    let temp = PZOFDT(X1, 温度_K, B, BI, C, CNS, K, K1, U);
    let FF1 = temp["P"];
    temp = PZOFDT(X2, 温度_K, B, BI, C, CNS, K, K1, U);
    let FF2 = temp["P"];

    FF1 = FF1 - 压力_MPa;
    FF2 = FF2 - 压力_MPa;

    if (FF1 * FF2 >= 0) {
        return
    }

    // '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    for (let I = 1; I <= 5000; I++) {
        D_unknown = (X1 + X2) / 2
        temp = PZOFDT(D_unknown, 温度_K, B, BI, C, CNS, K, K1, U)
        let FF = temp["P"];
        Z = temp["Z"];
        FF = FF - 压力_MPa;

        if (Math.abs(FF) < TOL) {
            break
        }
        if (FF * FF1 < 0) {
            X2 = D_unknown
        } else {
            X1 = D_unknown
        }
    }
    return Z;

}

function PZOFDT(D, T, B, BI, C, CNS, K, K1, U) {
    if (T < 230) {  // 如果燃气温度小于230，则说明单位是摄氏度，这里转为开尔文温度
        T = T + 273.15;
    }
    let R = 0.00831451;
    let DR = D * Math.pow(K1, 3);
    let P;
    let Z;
    let BMIX = 0;
    for (let n = 1; n <= 18; n++) {
        BMIX = BMIX + BI[n] / Math.pow(T, U[n])
    }

    Z = 1 + BMIX * D;

    for (let n = 13; n <= 18; n++) {
        Z = Z - DR * CNS[n] / Math.pow(T, U[n])
    }

    for (let n = 13; n <= 58; n++) {
        Z = Z + CNS[n] / Math.pow(T, U[n]) * (B[n] - C[n] * K[n] * Math.pow(DR, K[n])) * Math.pow(DR, B[n]) * Math.exp(-C[n] * Math.pow(DR, K[n]))
    }
    P = D * R * T * Z;
    return {P, Z};  // 返回的P迭代中间压力，Z是迭代终止时的压缩因子
}

function 密度_燃气(压力, 温度, 组分体积分数数组) {
    let z_gas = 压缩因子(压力, 温度, 组分体积分数数组);
    let rho_mole = 压力 / z_gas / 0.00831451 / (温度 + 273.15);
    let mass_mole = 摩尔质量_燃气(组分体积分数数组);
    return rho_mole * mass_mole;
}

function transpose(matrix) {
    let result = new Array(matrix.length).fill(0).map(arr => new Array(matrix[0].length).fill(0));
    for (let i = 0; i < result.length; i++) {
        for (let j = 0; j < result[0].length; j++) {
            result[i][j] = matrix[j][i];
        }
    }
    return result;
}

function 低位热值() {

}